package com.example.java_gobang.api;

import com.example.java_gobang.game.*;
import com.example.java_gobang.mapper.UserInfoMapper;
import com.example.java_gobang.model.UserInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class GameApi extends TextWebSocketHandler {
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RoomManager roomManager;
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        //1.先拿到用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            GameReadyResponse response = new GameReadyResponse();
            response.setOk(false);
            response.setReason("用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //2.判断当前用户是否已经进入房间
        Room room = roomManager.getRoomIdByUserId(userInfo.getUserId());
        if (room == null) {
            GameReadyResponse response = new GameReadyResponse();
            response.setOk(false);
            response.setReason("玩家未进入房间");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //3.判断玩家是否多开
        if (onlineUserManager.getFromRoom(userInfo.getUserId()) != null ||
                onlineUserManager.getFromMatch(userInfo.getUserId()) != null) {
            GameReadyResponse response = new GameReadyResponse();
            response.setOk(false);
            response.setReason("禁止玩家多开");
            response.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //4.玩家上线
        onlineUserManager.enterGameMatch(userInfo.getUserId(), session);
        System.out.println("玩家" + userInfo.getUsername() + "已经上线");
        //5.将玩家进入到游戏房间内
        //前面创建房间的过程是在game_hall.html页面完成并没有将玩家加入到房间内，
        //当前操作才是正式将玩家加入房间
        synchronized (room) {
            if (room.getPlayer1() == null) {
                room.setPlayer1(userInfo);
                System.out.println("玩家" + userInfo.getUsername() + "进入房间");

                return;
            }
            if (room.getPlayer2() == null) {
                room.setPlayer2(userInfo);
                //天梯积分少的先手，相同时默认是玩家1
                if (room.getPlayer1().getScore() <= room.getPlayer2().getScore()) {
                    room.setWhiteUser(room.getPlayer1().getUserId());
                } else {
                    room.setWhiteUser(room.getPlayer2().getUserId());
                }
                //当程序走到这里，说明两个玩家都已经进入房间，所以要给两名玩家返回响应
                //因为只会有一个玩家走到这里，所以要同时通知两名玩家
                //通知玩家1
                noticeGamePlay(room, room.getPlayer1(), room.getPlayer2());
                //通知玩家2
                noticeGamePlay(room, room.getPlayer2(), room.getPlayer1());
                System.out.println("玩家" + userInfo.getUsername() + "进入房间");
                return;
            }
        }

        //6.当有第三个人加入时，返回错误响应
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(false);
        response.setReason("当前房间已满");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGamePlay(Room room, UserInfo player1, UserInfo player2) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(true);
        response.setMessage("gameReady");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(player1.getUserId());
        response.setThatUserId(player2.getUserId());
        response.setIsWhite(room.getWhiteUser());
        WebSocketSession session = onlineUserManager.getFromMatch(player1.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    //处理落子逻辑
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //1.获取落子人的信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            GameReadyResponse response = new GameReadyResponse();
            response.setOk(false);
            response.setReason("用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //2.通过玩家找到对应房间
        Room room = roomManager.getRoomIdByUserId(userInfo.getUserId());
        room.putChess(message.getPayload());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromMatch(userInfo.getUserId());
        //防止在多开的情况下，第二个用户的退出连接操作，导致第一个用户也被影响
        if (exitSession == session) {
            onlineUserManager.exitGameMatch(userInfo.getUserId());
        }
        noticeThatUserWin(userInfo);
        System.out.println("玩家" + userInfo.getUsername() + "连接异常");
    }


    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get("user");
        if (userInfo == null) {
            return;
        }
        WebSocketSession exitSession = onlineUserManager.getFromMatch(userInfo.getUserId());
        //防止在多开的情况下，第二个用户的退出连接操作，导致第一个用户也被影响
        if (exitSession == session) {
            onlineUserManager.exitGameMatch(userInfo.getUserId());
        }
        noticeThatUserWin(userInfo);
        System.out.println("玩家" + userInfo.getUsername() + "退出游戏房间");
    }

    private void noticeThatUserWin(UserInfo userInfo) throws IOException {
        //1.根据玩家找到对应房间
        Room room = roomManager.getRoomIdByUserId(userInfo.getUserId());
        if (room == null) {
            //说明正常退出房间已经销毁
            return;
        }
        //2.根据房间找到对手
        UserInfo thatUser = (room.getPlayer1().getUserId() == userInfo.getUserId()) ? room.getPlayer2() : room.getPlayer1();
        //3.判断对手是否掉线
        WebSocketSession session = onlineUserManager.getFromMatch(thatUser.getUserId());
        if(session == null){
            //说明对手也掉线了
            roomManager.removeRoom(room.getRoomId(),room.getPlayer1().getUserId(),room.getPlayer2().getUserId());
            return;
        }
        //4.给对手发送胜利通知
        GameResponse response = new GameResponse();
        response.setWinner(thatUser.getUserId());
        response.setUserId(thatUser.getUserId());
        response.setMessage("putChess");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        //更新胜者败者信息
        userInfoMapper.updateWinUser(thatUser.getUserId());
        userInfoMapper.updateLoserUser(userInfo.getUserId());

        roomManager.removeRoom(room.getRoomId(),room.getPlayer1().getUserId(),room.getPlayer2().getUserId());
    }
}
